home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / c / library / dos / communic / pcmail / main / kbdinp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  15.9 KB  |  546 lines

  1. /*++
  2. /* NAME
  3. /*    kbdinp 3
  4. /* SUMMARY
  5. /*    keyboard interpreter
  6. /* PROJECT
  7. /*    pc-mail
  8. /* PACKAGE
  9. /*    mail
  10. /* SYNOPSIS
  11. /*    void kbdinp(screen)
  12. /*    Screen *screen;
  13. /*
  14. /*    void kbdinit()
  15. /*
  16. /*    void kbdrest()
  17. /*
  18. /*    int getkey()
  19. /* DESCRIPTION
  20. /*    The keyboard interpreter is the machine that executes the program
  21. /*    that is recorded in the form of Screen data structures.
  22. /*    Its task is to interpret keyboard input and to
  23. /*    invoke the appropriate action functions.
  24. /*
  25. /*    Depending on the return value of an action function
  26. /*    the keyboard interpreter i) returns (S_BREAK), ii) repaints the
  27. /*    screen (S_REDRAW), or iii) just waits for more keyboard
  28. /*    input. Error handling is entirely up to the action functions.
  29. /*
  30. /*    The routines in this module are responsible for what appears in the
  31. /*    top (function-key labels) and bottom sections (command dialogue)
  32. /*    of the tty screen.
  33. /*
  34. /*    The middle screen section is handled by the pager (except when
  35. /*    help info is displayed).
  36. /*
  37. /*    kbdinit() sets the tty driver and keypad modes (no echo,
  38. /*    punctual input).
  39. /*
  40. /*    kbrest() restores the modes to what they were when kbdinit() was
  41. /*    invoked.
  42. /*
  43. /*    getkey() returns the next keypress (see screen.h for function-key
  44. /*    codes) and maps lower case to upper case.
  45. /*
  46. /*    Terminal-specific codes for function keys and keypad are borrowed
  47. /*    from window.c.
  48. /* FUNCTIONS AND MACROS
  49. /*    printcl(), printat(), wputc(), wputs(), beep(), winout()
  50. /* SEE ALSO
  51. /*    window(3)       window management routines, function key codes
  52. /*    window(5)       window definitions
  53. /*    screen(3)       command key tables for each screen
  54. /*    screen(5)       structure of command key tables
  55. /* DIAGNOSTICS
  56. /*    It beeps when an illegal key is pressed. Otherwise, no error
  57. /*    handling at all.
  58. /* AUTHOR(S)
  59. /*    W.Z. Venema
  60. /*    Eindhoven University of Technology
  61. /*    Department of Mathematics and Computer Science
  62. /*    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  63. /* CREATION DATE
  64. /*    Thu Apr  2 18:43:12 GMT+1:00 1987
  65. /* LAST MODIFICATION
  66. /*    90/01/22 13:01:51
  67. /* VERSION/RELEASE
  68. /*    2.1
  69. /*--*/
  70.  
  71. #include <stdio.h>
  72. #include <signal.h>
  73. #include <ctype.h>
  74.  
  75. #include "defs.h"
  76. #include "mail.h"
  77. #include "screen.h"
  78. #include "window.h"
  79.  
  80. #ifdef  unix
  81. #if (SIII||SYSV)            /* AT&T */
  82. #include <termio.h>
  83. struct termio oldmode;
  84. #else                    /* V7 or Berkeley */
  85. #include <sgtty.h>
  86. struct sgttyb oldmode;
  87. # endif
  88. #endif
  89.  
  90. /* How to generate a brief delay when the user presses ESC */
  91.  
  92. #ifdef    MSDOS
  93. #define    sleep(x)    { unsigned i; for (i = 1; i > 0; i++) ; }
  94. #endif
  95.  
  96. /* Forward declarations */
  97.  
  98. hidden void kb_help();            /* Display context-sensitive help */
  99. hidden void kb_pause();            /* Press any key to continue */
  100. hidden int kb_paint();            /* Screen update routine */
  101. hidden int kb_str();            /* Read an arbitrary string */
  102. hidden int kb_key();            /* Read single-key input */
  103. hidden int kb_cr();            /* Allow ESC or ENTER as input */
  104. hidden int kb_edt();            /* String input with default */
  105. hidden int kb_yn();            /* Yes/no input */
  106. hidden char *kb_read();            /* Basic input function */
  107. hidden int input();            /* Read one key stroke */
  108. hidden int isempty();            /* String is all blanks */
  109.  
  110. /* Various strings */
  111.  
  112. #define QUEST   "? "            /* prompt for input */
  113. hidden char sect[] = "=========================================================\
  114. ======================";
  115.  
  116. /* The maximal length of string input; depends on the window size */
  117.  
  118. hidden int maxstr;
  119.  
  120. /* kbdinp - recursively interpret screen descriptions */
  121.  
  122. public int kbdinp(screen)
  123. Screen *screen;
  124. {
  125.     kb_paint(screen);
  126.  
  127.     if (iskey(screen->key))
  128.     return (kb_key(screen));        /* single-key commands */
  129.     else if (screen->key == STRING)
  130.     return (kb_str(screen));        /* string input screen */
  131.     else if (screen->key == EDIT)
  132.     return (kb_edt(screen));        /* string edit screen */
  133.     else if (screen->key == YESNO)
  134.     return (kb_yn(screen));            /* yes/no screen */
  135.     else if (screen->key == ESCCR)
  136.     return (kb_cr(screen));            /* confirm/cancel screen */
  137.     else
  138.     fatal("kbdinp");            /* unexpected screen type */
  139.     /* NOTREACHED */
  140. }
  141.  
  142. /* kb_paint - paint the screen (clean up this function) */
  143.  
  144. hidden int kb_paint(p)
  145. register Screen *p;
  146. {
  147.     char    topline[BUFSIZ];        /* key label line */
  148.     register int k;            /* loop control variable */
  149.     int     stat = 0;            /* status from mid window */
  150.     int     promptloc;            /* where prompt "?" goes */
  151.  
  152.     /*
  153.      * The top section of the screen consists of one line with key labels (in
  154.      * case of single-key input screen) and a bar that separates this section
  155.      * from the middle screen section.
  156.      * 
  157.      * We always add a Help and ? label. Thus, the interpreter preempts the 
  158.      * use of the H and ? characters.
  159.      */
  160.  
  161.     for (topline[0] = 0; p->key; p++) {        /* start top window */
  162.     if (iskey(p->key)) {            /* keystroke input ? */
  163.         strcat(topline, p->name);        /* append key label */
  164.         strcat(topline, "  ");        /* and some blanks */
  165.     } else if (topline[0]) {        /* leak if first entry */
  166.         fatal("mixed single-key and string input");
  167.     }
  168.     }
  169.     printcl(topwin, 0, topline);        /* display key labels */
  170.     if (topline[0])                /* if there are labels */
  171.     wputs("Help ?");            /* display help key labels */
  172.     printcl(topwin, 1, sect);            /* finish top window with bar */
  173.  
  174.     /*
  175.      * The bottom section of the screen consists of a bar that separates us
  176.      * from the middle section, followed by the "help" string in the last
  177.      * entry of the current screen definition, followed by (if not a
  178.      * single-key input screen) a prompting question mark.
  179.      */
  180.  
  181.     printcl(botwin, 0, sect);            /* start lower window */
  182.     promptloc = printcl(botwin, 1, p->help ? p->help : "") + 1;
  183.     for (k = promptloc; k < botwin->size; k++)    /* clear rest of lower window */
  184.     printcl(botwin, k, "");            /* lower window done */
  185.  
  186.     if (p->action)                /* fill middle window */
  187.     stat = CALL(p->action) ();        /* middle window done */
  188.  
  189.     /* 
  190.      * We leave the focus on the middle window, in case of single-key input,
  191.      * and move the focus to the bottom window in case of prompted input.
  192.      */
  193.  
  194.     if (topline[0] == 0)            /* prompted input screen? */
  195.     printat(botwin, promptloc, QUEST);    /* output "?" prompt */
  196.  
  197.     /* Determine maximal length of string input */
  198.  
  199.     maxstr = MAX(((botwin->size - 1) * CO - sizeof(QUEST) - 2), BUFSIZ - 1);
  200.  
  201.     return (stat);                /* from middle window filler */
  202. }
  203.  
  204. /* kb_str - handle string input without defaults */
  205.  
  206. hidden int kb_str(p)
  207. register Screen *p;
  208. {
  209.     char    string[BUFSIZ];        /* a character buffer */
  210.     register int stat;
  211.  
  212.     for (;;) {
  213.     string[0] = '\0';            /* no default input */
  214.     if (kb_read(string) == 0) {        /* command cancelled? */
  215.         return (0);                /* quit */
  216.     } else if ((stat = CALL(p->action) (string)) & S_BREAK) {
  217.         return (stat);            /* we're done here */
  218.     } else if (stat & S_REDRAW) {        /* screen was changed */
  219.         kb_paint(p);            /* restore display */
  220.     }
  221.     }
  222. }
  223.  
  224. /* kb_yn - handle yes/no input */
  225.  
  226. hidden int kb_yn(p)
  227. register Screen *p;
  228. {
  229.     char    string[BUFSIZ];        /* a character buffer */
  230.     register int stat;            /* return status */
  231.     static char yn[] = "nNyY";        /* input is not mapped to upper case */
  232.     char   *in;
  233.  
  234.     for (string[0] = '\0';;) {            /* clear input */
  235.     if (kb_read(string) == 0) {        /* command cancelled? */
  236.         return (0);                /* quit */
  237.     } else if ((in = index(yn, string[0])) == 0) {    /* validate */
  238.         beep();                /* complain */
  239.         kb_paint(p);            /* restore display */
  240.     } else if ((stat = CALL(p->action) (in - yn > 1)) & S_BREAK) {
  241.         return (stat);            /* we're done here */
  242.     } else if (stat & S_REDRAW) {        /* screen was changed */
  243.         kb_paint(p);            /* restore display */
  244.         string[0] = '\0';            /* clear input */
  245.     }
  246.     }
  247. }
  248.  
  249. /* kb_edt - handle string input with default */
  250.  
  251. hidden int kb_edt(p)
  252. register Screen *p;
  253. {
  254.     char    string[BUFSIZ];        /* user input */
  255.     register int stat;            /* return status */
  256.  
  257.     for (;;) {
  258.     (void) strncpy(string, p->help, BUFSIZ);/* stuff default input */
  259.     if (kb_read(string) == 0) {        /* command cancelled */
  260.         return (0);                /* quit */
  261.     } else if ((stat = CALL(p->action) (string)) & S_BREAK) {
  262.         return (stat);            /* we're done here */
  263.     } else if (stat & S_REDRAW) {        /* screen was changed */
  264.         kb_paint(p);            /* restore display */
  265.     }
  266.     }
  267. }
  268.  
  269. /* kb_read - general string edit/input routine */
  270.  
  271. hidden char *kb_read(string)
  272. char    string[BUFSIZ];
  273. {
  274.     register char *cp;            /* a character pointer */
  275.     register int c;            /* a character */
  276.  
  277.     cp = string + strlen(string);        /* update buffer pointer */
  278.     wputs(string);                /* show input to be edited */
  279.  
  280.     for (;;) {
  281.     if (!isascii(c = input())) {        /* ignore non-ascii codes */
  282.         beep();                /* complain */
  283.     } else if (c == ESC) {            /* ESC means don't do it */
  284.         wputs(" (ESC)");            /* confirm input */
  285.         sleep(1);
  286.         return (0);                /* nothing left here to do */
  287.     } else if (c == ENTER && (*cp = 0, !isempty(string))) {
  288.         wputc(c);                /* echo */
  289.         return (string);            /* we're done here */
  290.     } else if (c == BS || c == DEL) {
  291.         if (cp > string)
  292.         cp--, wputs("\b \b");        /* remove one character */
  293.     } else if (c == CTLU) {            /* line erase */
  294.         while (cp > string)
  295.         cp--, wputs("\b \b");
  296.     } else if ((c == ' ' || isprint(c)) && (cp - string) < maxstr) {
  297.         wputc(*cp++ = c);            /* accept and echo */
  298.     } else {
  299.         beep();                /* complain */
  300.     }
  301.     }
  302. }
  303.  
  304. /* kb_key - handle single-key input */
  305.  
  306. hidden int kb_key(p)
  307. Screen *p;
  308. {
  309.     register int c;            /* a character */
  310.     register Screen *q;            /* a screen (eh?) */
  311.     register int stat;            /* a status */
  312.  
  313.     for (;;) {
  314.     if ((c = getkey()) == '?' || c == 'H') {/* is it a help request */
  315.         kb_help(p);                /* yes, display key info */
  316.         continue;                /* skip rest of loop */
  317.     }
  318.     for (q = p; q->key && q->key != c; q++)    /* look key up in table */
  319.         /* void */
  320.         ;
  321.     if (q->key == 0) {            /* unrecognized key */
  322.         beep();                /* complain */
  323.     } else if (q->action == 0) {        /* action-less key */
  324.         return (0);                /* we are done here */
  325.     } else if ((stat = CALL(q->action) ()) & S_BREAK) {    /* do action */
  326.         return (stat);            /* we are done here */
  327.     } else if (stat & S_REDRAW) {        /* screen was changed */
  328.         kb_paint(p);            /* restore screen */
  329.     }
  330.     }
  331. }
  332.  
  333. /* kb_cr - handle escape/enter input */
  334.  
  335. hidden int kb_cr(p)
  336. Screen *p;
  337. {
  338.     register int c;
  339.     register int stat;
  340.  
  341.     for (;;) {
  342.     if ((c = input()) == ESC) {        /* don't do it */
  343.         wputs(" (ESC)");            /* confirm input */
  344.         sleep(1);
  345.         return (0);                /* we are done */
  346.     } else if (c == ENTER) {        /* do the action */
  347.         stat = CALL(p->action) ();        /* execute action */
  348.         if (stat & S_BREAK) {        /* child kills parent */
  349.         return (stat);            /* we are done */
  350.         } else if (stat & S_REDRAW) {    /* screen was changed */
  351.         kb_paint(p);            /* restore screen */
  352.         }
  353.     } else {                /* unacceptable input */
  354.         beep();                /* complain */
  355.     }
  356.     }
  357. }
  358.  
  359. /* kb_help - display per-key help info; redraw screen when done */
  360.  
  361. hidden void kb_help(p)
  362. register Screen *p;
  363. {
  364.     register int k;
  365.  
  366.     for (k = 0; k < midwin->size; k++)        /* erase middle window */
  367.     printcl(midwin, k, "");
  368.     for (k = 0; p[k].key; k++)            /* display key info */
  369.     printcl(midwin, k + 1, strcons("   %-10s %s", isascii(p[k].key) && 
  370.         isprint(p[k].key) ? p[k].name[1] ? strcons("%c(%s)", p[k].key, 
  371.         p[k].name + 1) : strcons("%c", p[k].key) : p[k].name, p[k].help));
  372.     for (k = 1; k < botwin->size - 1; k++)    /* erase bottom window */
  373.     printcl(botwin, k, "");
  374.     printcl(botwin, 1, anykey);            /* press any key to continue */
  375.     getkey();
  376.     kb_paint(p);                /* redraw screen */
  377. }
  378.  
  379. /* structure that associates token value with function-key strings */
  380.  
  381. struct keydef {
  382.     char  **strval;            /* key string */
  383.     int     tokval;            /* key value */
  384. };
  385.  
  386. hidden struct keydef keys[] = {
  387.     &KU, UP,                /* key strings are set */
  388.     &KD, DOWN,                /* in window.c */
  389.     &KL, LEFT,
  390.     &KR, RIGHT,
  391.     &PU, PGUP,
  392.     &PD, PGDN,
  393.     0, 0,
  394. };
  395.  
  396. /* getkey - get key stroke, detect function keys, ignore case otherwise */
  397.  
  398. public int getkey()
  399. {
  400.     register int c;
  401.     register struct keydef *kp;
  402.     char    kstr[BUFSIZ];
  403.     register int len;
  404.  
  405.     /*
  406.      * We assume that all function keys produce strings that start with the
  407.      * same lead-in character, and that those strings all have the same
  408.      * length. This is a reasonable assumption for cursor-control keys on
  409.      * most terminals.
  410.      */
  411.  
  412.     if ((c = input()) == **(keys->strval)) {    /* lead-in character */
  413.  
  414.     /*
  415.      * Read a number of characters equal to the length of the strings
  416.      * generated by function keys.
  417.      */
  418.  
  419.     for (len = 1; len < strlen(*(keys[0].strval)); len++)
  420.         kstr[len] = c = input();
  421.     kstr[len] = '\0';
  422.  
  423.     /* Compare what we just read with known function-key strings. */
  424.  
  425.     for (kp = keys; kp->tokval; kp++)
  426.         if (strcmp(*(kp->strval) + 1, kstr + 1) == 0)
  427.         return (kp->tokval);        /* return token value */
  428.     }
  429.     /* Return the last read character. */
  430.  
  431.     return ((isascii(c) && islower(c)) ? toupper(c) : c);
  432. }
  433.  
  434. /* input - read one character without echoing or waiting for carriage return */
  435.  
  436. hidden int input()
  437. {
  438.  
  439. #ifdef    unix
  440.  
  441.     /*
  442.      * On unix systems, the terminal driver has been instructed to not echo
  443.      * and to return one character as soon as it comes available. Also the
  444.      * stdio routines have been instructed to process input in an unbuffered
  445.      * fashion. See kbdinit().
  446.      */
  447.  
  448.     return (getchar());
  449. #endif
  450.  
  451. #ifdef    MSDOS
  452.  
  453.     /*
  454.      * On IBM-PC machines a function key produces a null character followed
  455.      * by a scan code. We translate the null prefix to an escape character
  456.      * since that is more like normal terminals do. The trick is to find out
  457.      * when we read a null character whether it was produced by pressing a
  458.      * real function-key or by pressing ctrl-@.
  459.      */
  460.  
  461.     register int c;
  462.  
  463.     return ((c = getch()) ? c : kbhit() ? ESC : 0);
  464. #endif
  465.  
  466. #if (!defined(unix) && !defined(MSDOS))
  467.     "You should either define unix or MSDOS, or add support for another OS"
  468. #endif
  469. }
  470.  
  471. /* kbdinit - set input mode, turn keypad on */
  472.  
  473. public void kbdinit()
  474. {
  475.  
  476. #ifdef    MSDOS
  477.     (void) signal(SIGINT, SIG_IGN);    /* ignore control-c */
  478. #endif
  479.  
  480. #ifdef  unix
  481.  
  482.     /*
  483.      * On unix systems, instruct the terminal driver to not echo terminal
  484.      * input, and to return from a read as soon as one character comes
  485.      * available.
  486.      */
  487.  
  488. # if (SIII||SYSV)
  489.     struct termio newmode;        /* AT&T */
  490.  
  491.     (void) ioctl(0, TCGETA, &oldmode);        /* save terminal mode */
  492.     (void) ioctl(0, TCGETA, &newmode);        /* get terminal mode */
  493.     newmode.c_iflag &= ~(ICRNL | BRKINT);
  494.     newmode.c_oflag &= ~OPOST;
  495.     newmode.c_lflag &= ~(ICANON | ISIG | ECHO);
  496.     newmode.c_cc[VMIN] = 1;
  497.     newmode.c_cc[VTIME] = 0;
  498.     (void) ioctl(0, TCSETAF, &newmode);        /* set terminal mode */
  499. # else
  500.     struct sgttyb newmode;        /* V7 or Berkeley */
  501.  
  502.     (void) gtty(0, &oldmode);            /* save terminal mode */
  503.     (void) gtty(0, &newmode);            /* get terminal mode */
  504.     newmode.sg_flags |= RAW;
  505.     newmode.sg_flags &= ~(ECHO | CRMOD);
  506.     (void) stty(0, &newmode);            /* set terminal mode */
  507. # endif
  508.  
  509.     setbuf(stdin, (char *) 0);            /* select unbuffered input */
  510.  
  511.     if (KS && *KS)                /* if there is a keypad */
  512.     tputs(KS, 1, fputchar);            /* enable it */
  513. #endif
  514. }
  515.  
  516. /* kbdrest - reset terminal driver to previous state, turn keypad off */
  517.  
  518. public void kbdrest()
  519. {
  520. #ifdef  unix
  521.  
  522.     /* Restore tty modes, either the AT&T way or the BSD+V7 way */
  523.  
  524. # if (SIII||SYSV)
  525.     ioctl(0, TCSETAF, &oldmode);
  526. # else
  527.     stty(0, &oldmode);
  528. # endif
  529.  
  530.     /* Disable keypad if there is one */
  531.  
  532.     if (KE && *KE)
  533.     tputs(KE, 1, fputchar);
  534. #endif
  535. }
  536.  
  537. /* isempty - check a string is all blanks or empty */
  538.  
  539. hidden int isempty(s)
  540. register char *s;
  541. {
  542.     while (*s && isspace(*s))
  543.     s++;
  544.     return (*s == 0);
  545. }
  546.